#include "variate.h"


Variate::Variate(Variate::Type type) : data_()
{
    flag_ = type;
}

Variate::Variate(int i) : data_() {
    SetInt(i);
}

Variate::Variate(uint32_t u) : data_() {
    SetUint(u);
}

Variate::Variate(float f) : data_() {
    SetFloat(f);
}

#ifdef EN_64bit
Variate::Variate(int64_t i64) : data_() {
    SetInt64(i64);
}

Variate::Variate(uint64_t u64) : data_() {
    SetUint64(u64);
}

Variate::Variate(double d) : data_() {
    SetDouble(d);
}
#endif

Variate::Variate(const char *s) : data_() {
    SetStringRaw(s);
}

Variate::~Variate() {
    if (flag_ == kStringFlag) {
        const char *ptr = GetStringPointer();
        if (ptr)
            delete [] ptr;
    }
}

float Variate::GetFloat() const {
    ASSERT(IsNumber());
    if ( (flag_ == kFloatFlag) )   return data_.n.f;
    if ( (flag_ == kIntFlag) )     return data_.n.i; // int -> float
    if ( (flag_ == kUintFlag) )    return data_.n.u; // unsigned -> float
#ifdef EN_64bit
    if ( (flag_ == kDoubleFlag) )  return static_cast<float>(data_.n.d);   // double -> float (may lose precision)
    if ( (flag_ == kInt64Flag) )   return static_cast<float>(data_.n.i64); // int64_t -> float (may lose precision)
    if ( (flag_ == kUint64Flag) )  return static_cast<float>(data_.n.u64); // uint64_t -> float (may lose precision)
#endif
    ASSERT(false);
    return 0.0;
}

#ifdef EN_64bit
double Variate::GetDouble() const {
    ASSERT(IsNumber());
    if ( (flag_ == kDoubleFlag) )  return data_.n.d;   // exact type, no conversion.
    if ( (flag_ == kFloatFlag) )   return static_cast<double>(data_.n.f);
    if ( (flag_ == kIntFlag) )     return data_.n.i; // int -> double
    if ( (flag_ == kUintFlag) )    return data_.n.u; // unsigned -> double
    if ( (flag_ == kInt64Flag) )   return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
    if ( (flag_ == kUint64Flag) )  return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
    ASSERT(false);
    return 0.0;
}
#endif


Variate &Variate::SetInt(int i)
{
    if (IsString())
        this->~Variate();

    data_.n.i = i;
    flag_ = kIntFlag;
    return *this;
}

Variate &Variate::SetUint(unsigned u)
{
    if (IsString())
        this->~Variate();

    data_.n.u = u;
    flag_ = kUintFlag;
    return *this;
}

Variate &Variate::SetFloat(float f)
{
    if (IsString())
        this->~Variate();

    data_.n.f = f;
    flag_ = kFloatFlag;
    return *this;
}


#ifdef EN_64bit
Variate &Variate::SetInt64(int64_t i64)
{
    if (IsString())
        this->~Variate();

    data_.n.i64 = i64;
    flag_ = kIntFlag;
    return *this;
}

Variate &Variate::SetUint64(uint64_t u64)
{
    if (IsString())
        this->~Variate();

    data_.n.u64 = u64;
    flag_= kUint64Flag;
    return *this;
}

Variate &Variate::SetDouble(double d)
{
    if (IsString())
        this->~Variate();

    data_.n.d = d;
    flag_ = kDoubleFlag;
    return *this;
}
#endif


void Variate::SetStringRaw(const char *s) {
    flag_ = kStringFlag;
    size_t len = strlen(s);
    char *str = new char[len+1];
    SetStringPointer(str);
    memcpy(str, s, len);
    str[len] = '\0';
}
